package bus

import chisel3._
import chisel3.util._
import utils._

object AHBParameters
{
  // These are all fixed by the AHB standard:
  val transBits = 2
  val burstBits = 3
  val protBits  = 4
  val sizeBits  = 3  // 8*2^s
//   val userBits  = 3
  val hrespBits = 2  // AHB full

  def TRANS_IDLE   = 0.U(transBits.W) // No transfer requested, not in a burst
  def TRANS_BUSY   = 1.U(transBits.W) // No transfer requested, in a burst
  def TRANS_NONSEQ = 2.U(transBits.W) // First (potentially only) request in a burst
  def TRANS_SEQ    = 3.U(transBits.W) // Following requests in a burst

  def BURST_SINGLE = 0.U(burstBits.W) // Single access (no burst)
  def BURST_INCR   = 1.U(burstBits.W) // Incrementing burst of arbitrary length, not crossing 1KB
  def BURST_WRAP4  = 2.U(burstBits.W) // 4-beat wrapping burst
  def BURST_INCR4  = 3.U(burstBits.W) // 4-beat incrementing burst
  def BURST_WRAP8  = 4.U(burstBits.W) // 8-beat wrapping burst
  def BURST_INCR8  = 5.U(burstBits.W) // 8-beat incrementing burst
  def BURST_WRAP16 = 6.U(burstBits.W) // 16-beat wrapping burst
  def BURST_INCR16 = 7.U(burstBits.W) // 16-beat incrementing burst

  val maxTransfer = 16

  def RESP_OKAY  = 0.U(2.W)
  def RESP_ERROR = 1.U(2.W)
  // Only in AHB-Full:
  def RESP_RETRY = 2.U(2.W)
  def RESP_SPLIT = 3.U(2.W)

  def PROT_DATA        = 1.U(protBits.W)
  def PROT_PRIVILEGED  = 2.U(protBits.W)
  def PROT_BUFFERABLE  = 4.U(protBits.W)
  def PROT_CACHEABLE   = 8.U(protBits.W)
  def PROT_DEFAULT = PROT_DATA | PROT_PRIVILEGED
}

case class AhbConfig(
    extendLite: Boolean,
    busReqHold: Boolean,
    auserBits : Int = 0,
    duserBits : Int = 0,
    addrBits  : Int,
    dataBits  : Int,
    lite      : Boolean
){
    val transBits = AHBParameters.transBits
    val sizeBits = AHBParameters.sizeBits
    val burstBits = AHBParameters.burstBits
    val protBits = AHBParameters.protBits
    val hrespBits = AHBParameters.hrespBits
}

class AhbBundle(val params: AhbConfig) extends Bundle {
    // Control signals from master to arbiter
    val hmastlock = if (params.lite) Some(Output(Bool())) else None
    val hlock     = if (params.lite) None else Some(Output(Bool()))
    val hbusreq   = if (params.lite) None else Some(Output(Bool()))

    // Flow control from arbiter to master
    val hgrant  = if (params.lite) None else Some(Input(Bool()))
    val hready  = Input(Bool())

    // Handy methods that don't care about lite
    def lock():   Bool = if (params.lite) hmastlock.get else hlock.get
    def busreq(): Bool = if (params.lite) true.B else hbusreq.get
    def grant():  Bool = if (params.lite) true.B else hgrant.get

    // A-phase signals from master to arbiter
    val htrans  = Output(UInt(params.transBits.W))
    val hsize   = Output(UInt(params.sizeBits.W))
    val hburst  = Output(UInt(params.burstBits.W))
    val hwrite  = Output(Bool())
    val hprot   = Output(UInt(params.protBits.W))
    val haddr   = Output(UInt(params.addrBits.W))
    val hauser  = if (params.auserBits == 0) None else Some(Output(UInt(params.auserBits.W)))

    // D-phase signals from master to arbiter
    val hduser  = if (params.auserBits == 0) None else Some(Output(UInt(params.auserBits.W)))
    val hwdata  = Output(UInt(params.dataBits.W))

    // D-phase response from arbiter to master
    val hresp   = Input(UInt(params.hrespBits.W))
    val hrdata  = Input(UInt(params.dataBits.W))

    // Extend AHB lite signal  TODO:
    // val hsel = if (params.extendLite) Some(Output(Bool())) else None
    // val hreadyOut = if (params.extendLite) Some(Output(Bool())) else None
    // def getHsel(): Bool = if (params.extendLite) hsel.get else true.B
    // def getHreadyOut(): Bool = if (params.extendLite) hreadyOut.get else true.B
}

object AhbConfigObject{
    def apply():AhbConfig = {
        AhbConfig(
            extendLite = true,
            busReqHold = true,
            auserBits  = 0,
            duserBits  = 0,
            addrBits   = 32,
            dataBits   = 64,
            lite       = true
        )
    }
}